﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

namespace WpfVoronoiDllTest
{   //GeometryTools
    public static class Gt
    {
   
    
         //BorderIntersection
        public static BenTools.Mathematics.Vector BorderIntersection(BenTools.Mathematics.Vector FixedPoint, BenTools.Mathematics.Vector VertexB, double aWidth, double aHeight )
         
         { //Top
             
           //  Left Right Botton
             Point I = new Point ();
             Point A = new Point (FixedPoint[0],FixedPoint[1]);
             Point B = new Point (VertexB[0],VertexB[1]);

            //faltan los if true
             if (SegSegIntersection(A, B, new Point(0, 0), new Point(aWidth, 0), ref I)) { return new BenTools.Mathematics.Vector(I.X, I.Y); }
             if (SegSegIntersection(A, B, new Point(0, 0), new Point(0,aHeight),ref I)){ return new BenTools.Mathematics.Vector(I.X,I.Y);}
             if (SegSegIntersection(A, B, new Point(aWidth, 0), new Point(aWidth,aHeight), ref I)){ return new BenTools.Mathematics.Vector(I.X,I.Y);}
             if (SegSegIntersection(A, B, new Point(0, aHeight), new Point(aWidth, aHeight),ref I)){ return new BenTools.Mathematics.Vector(I.X,I.Y);}

             return VertexB;// Oustide bounds
            //return new BenTools.Mathematics.Vector(I.X, I.Y);
          
         }

        //Outside 
        public static bool OutsideBound(BenTools.Mathematics.Vector A, double aWidth, double aHeight)
        { 
            double Ax = A[0];
            double Ay = A[1];

            if (Ax < 0 || Ax > aWidth) return true;
            if (Ay < 0 || Ay > aHeight) return true;
            return false;           

        }


        public static List<Point> PolygonInset(List<Point> Poligono, double inset)
        {
            List<Point> Result = new List<Point>();
            //Point insPnt = new Point();
            int cant = Poligono.Count;
            int i, i1, i2;
            //Work in a circle
            for (i = 0; i < cant; i++)
            {
                i1 = (i + 1) % cant;
                i2 = (i + 2) % cant;
                // Console.WriteLine("i:" +i.ToString() + " i1:" + i1.ToString() + "i2:" +i2.ToString() );		 
                Result.Add(PointInset(Poligono[i], Poligono[i1], Poligono[i2], inset));

                //Console.WriteLine("O :" + Poligono[i1].X.ToString() + " Y:" + Poligono[i1].Y.ToString());
                //Console.WriteLine("np:" + Result[i].X.ToString() + " Y:" + Result[i].Y.ToString());

            }
            return Result;
        }

        // Inset Point B the insetDist
        public static Point PointInset(Point A, Point B, Point C, double insetDist)
        {
            /*double  Ax a; double  Ay b;   // A previous point
            double  Bx c; double  By d;   //  B current point that needs to be inset
            double  Cx e; double  Cy f;   //  C next point
            double *C; double *D;   //  I storage location for new, inset point
            */
            double A2x, A2y, B1x, B1y, B2x, B2y, C2x, C2y, dx1, dy1, dist1, dx2, dy2, dist2, insetX, insetY;

            //  Calculate length of line segments.
            dx1 = B.X - A.X; dy1 = B.Y - A.Y; dist1 = Math.Sqrt(dx1 * dx1 + dy1 * dy1);
            dx2 = C.X - B.X; dy2 = C.Y - B.Y; dist2 = Math.Sqrt(dx2 * dx2 + dy2 * dy2);

            //  Exit if either segment is zero-length.
            // if (dist1==0 || dist2==0) return;

            //  Inset each of the two line segments.
            // Calculate normal point win cos * inset
            insetX = dy1 / dist1 * insetDist; A2x = A.X + insetX; B1x = B.X + insetX;
            insetY = -dx1 / dist1 * insetDist; A2y = A.Y + insetY; B1y = B.Y + insetY;

            insetX = dy2 / dist2 * insetDist; C2x = C.X + insetX; B2x = B.X + insetX;
            insetY = -dx2 / dist2 * insetDist; C2y = C.Y + insetY; B2y = B.Y + insetY;

            //  If inset segments connect perfectly, return the connection point.
            Point I = new Point(0, 0);
            /*
            if (B1x==B2x && B1y==B2y) {
              I.X=B1x; I.Y=B1y; return I ; }
              */
            //  Return the intersection point of the two inset segments (if any).
            if (RayIntersection(new Point(A2x, A2y), new Point(B1x, B1y), new Point(B2x, B2y), new Point(C2x, C2y), ref I))
            {
                return I;
                //I.X=insetX; I.Y=insetY; 
                // To fix it
            }

            return I;
        }


        
        //---------------------------
        // RayIntersection
        public static bool RayIntersection(Point A, Point B, Point C, Point D, ref Point I)
        {
            I = new Point();

            double Ax = A.X; double Ay = A.Y; double Bx = B.X; double By = B.Y;
            double Cx = C.X; double Cy = C.Y; double Dx = D.X; double Dy = D.Y;

            double distAB, theCos, theSin, newX, ABpos;

            //  Fail if either line is undefined.
            if (Ax == Bx && Ay == By || Cx == Dx && Cy == Dy) return false;

            //  (1) Translate the system so that point A is on the origin.
            Bx -= Ax; By -= Ay;
            Cx -= Ax; Cy -= Ay;
            Dx -= Ax; Dy -= Ay;

            //  Discover the length of segment A-B.
            distAB = System.Math.Sqrt(Bx * Bx + By * By);

            //  (2) Rotate the system so that point B is on the positive X axis.
            theCos = Bx / distAB;
            theSin = By / distAB;
            newX = Cx * theCos + Cy * theSin;
            Cy = Cy * theCos - Cx * theSin; Cx = newX;
            newX = Dx * theCos + Dy * theSin;
            Dy = Dy * theCos - Dx * theSin; Dx = newX;

            //  Fail if the lines are parallel.
            if (Cy == Dy) return false;

            //  (3) Discover the position of the intersection point along line A-B.
            ABpos = Dx + (Cx - Dx) * Dy / (Dy - Cy);

            //  (4) Apply the discovered position to line A-B in the original coordinate system.
            I.X = Ax + ABpos * theCos;
            I.Y = Ay + ABpos * theSin;

            //  Success.
            return true;
        }
        // funcion que indica si hay interseccion
        // SegSegIntersection
        //---------------------------------------------------------	
        // http://alienryderflex.com/intersect/
        //---------------------------------------------------------	

        public static bool SegSegIntersection(Point A, Point B, Point C, Point D, ref Point I)
        {
            I = new Point();
            double LAx = A.X; double LAy = A.Y; double LBx = B.X; double LBy = B.Y;
            double SCx = C.X; double SCy = C.Y; double SDx = D.X; double SDy = D.Y;
            double distAB, theCos, theSin, newX, ABpos;

            //  Fail if either line segment is zero-length.
            if (LAx == LBx && LAy == LBy || SCx == SDx && SCy == SDy) return false;

            //  Fail if the segments share an end-point.
            if (LAx == SCx && LAy == SCy || LBx == SCx && LBy == SCy
            || LAx == SDx && LAy == SDy || LBx == SDx && LBy == SDy) { return false; }

            //  (1) Translate the system so that point A is on the origin.
            LBx -= LAx; LBy -= LAy;
            SCx -= LAx; SCy -= LAy;
            SDx -= LAx; SDy -= LAy;

            //  Discover the length of segment A-B.
            distAB = System.Math.Sqrt(LBx * LBx + LBy * LBy);

            //  (2) Rotate the system so that point B is on the positive X LAxis.
            theCos = LBx / distAB;
            theSin = LBy / distAB;
            newX = SCx * theCos + SCy * theSin;
            SCy = SCy * theCos - SCx * theSin; SCx = newX;
            newX = SDx * theCos + SDy * theSin;
            SDy = SDy * theCos - SDx * theSin; SDx = newX;

            //  Fail if segment C-D doesn't cross line A-B.
            if (SCy < 0 && SDy < 0 || SCy >= 0 && SDy >= 0) return false;

            //  (3) Discover the position of the intersection point along line A-B.
            ABpos = SDx + (SCx - SDx) * SDy / (SDy - SCy);

            //  Fail if segment C-D crosses line A-B outside of segment A-B.
            if (ABpos < 0 || ABpos > distAB) return false;

            //  (4) Apply the discovered position to line A-B in the original coordinate system.
            I.X = LAx + ABpos * theCos;
            I.Y = LAy + ABpos * theSin;

            //  Success.
            return true;

        }
        
         


        // Angle Betwen Center and Point
        public static double Angle(Point A, Point center)
        {
            double angle = Math.Acos((A.X - center.X) / PointDistance(center, A));
            if (A.Y < center.Y)
            {
                angle = Math.PI + Math.PI - angle;//360-angle
            }              
            return angle; //return angle*180/Math.PI;
        }
        // Distance betwen two point
        public static double PointDistance(Point A, Point B)
        {
            return Math.Sqrt(Math.Pow(A.X - B.X, 2) + Math.Pow(A.Y - B.Y, 2));
        }

          // Distance betwen two Vector
        public static double VectorDistance(BenTools.Mathematics.Vector A, BenTools.Mathematics.Vector B) 
        {

            return Math.Sqrt(Math.Pow(A[0] - B[0], 2) + Math.Pow( A[1] - B[1], 2));
        }
          // Distance betwen two InpcPointData

        public static double InpcPointDataDistance(InpcPointData A, Point B)
        {
            return Math.Sqrt(Math.Pow(A.X - B.X, 2) + Math.Pow(A.Y - B.Y, 2));
        }

        // Punto en el medio de la linea
        public static Point HalfPointOfLine(Point start, Point end)
        {                       
            double deltaX = (end.X - start.X) * 0.5;
            double deltaY = (end.Y - start.Y) * 0.5;
            return new Point(start.X + deltaX, start.Y + deltaY);
        }

        // Punto en el medio de la linea
        public static BenTools.Mathematics.Vector HalfPointOfLine(double startX, double startY, double endX, double endY)
        {
            double deltaX = (endX - startX) * 0.5;
            double deltaY = (endY - startY) * 0.5;
            return new BenTools.Mathematics.Vector(startX + deltaX, startY + deltaY);            
        }
        // PolygonCenter
        public static Point PolygonCenter(System.Windows.Media.PointCollection PolPoints)
        {
            if (PolPoints.Count == 0) return new Point(0, 0);
            // calculate max and min x and y
            double minX = PolPoints[0].X;
            double maxX = PolPoints[0].X;
            double minY = PolPoints[0].Y;
            double maxY = PolPoints[0].Y;

            foreach (Point ipoint in PolPoints)
            {
                if (ipoint.X < minX) minX = ipoint.X;
                if (ipoint.X > maxX) maxX = ipoint.X;
                if (ipoint.Y < minY) minY = ipoint.Y;
                if (ipoint.Y > maxY) maxY = ipoint.Y;
            }

            return new Point(minX + (maxX - minX) / 2, minY + (maxY - minY) / 2);
        }
        // PolygonScale
        public static System.Windows.Media.PointCollection PolygonScale(System.Windows.Media.PointCollection Poligono, double scale)
        {
            //List<Point> Result = new List<Point>();
            System.Windows.Media.PointCollection Result = new System.Windows.Media.PointCollection();
            Point center = PolygonCenter(Poligono);
         
            foreach (Point ipoint in Poligono)
            {
                
                Result.Add(SegmentScale(center, ipoint, scale));
            }
            return Result;
            //return true;
        }
        // Scale segment
        public static Point SegmentScale(Point start, Point end, double scalar)
        {
            //double scalar = 0.5;
            double deltaX = (end.X - start.X) * scalar;
            double deltaY = (end.Y - start.Y) * scalar;
            return new Point(start.X + deltaX, start.Y + deltaY);
        }
	       
      
    }
}
